
package com.epam.android.training.day11.task1;

import android.app.Activity;
import android.content.Intent;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ImageButton;
import android.widget.ListView;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

/**
 * Simple media player activity that supports all android compartible audio
 * formats. Provides play, pause, next and previous funcionality. Traks to
 * playlist could be added from device file system.
 * 
 * @author Anton Novikau
 */
public class Player extends Activity {

  private static final String TAG = Player.class.getSimpleName();

  private static final int FILE_PICKER = 0;

  private ListView playList;

  private ArrayAdapter<String> playListAdapter;

  private Map<Integer, String> playListContent;

  private MediaPlayer player;

  /**
   * index in playlist of currently played track.
   */
  private int currentlyPlayed;

  /** Called when the activity is first created. */
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    playList = (ListView) findViewById(R.id.play_list);

    // restore configuration if it was saved before or initialize player and
    // playlist otherwise.
    ConfigurationHolder configuration = (ConfigurationHolder) getLastNonConfigurationInstance();
    if (configuration == null) {
      player = new MediaPlayer();
      addPlayerOnCompleteAction();

      playListContent = new HashMap<Integer, String>();

      playListAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1,
          android.R.id.text1, new ArrayList<String>());
    } else {
      player = configuration.player;
      playListContent = configuration.playListContent;
      playListAdapter = configuration.playListAdapter;
    }
    playList.setAdapter(playListAdapter);

    addSelectTrackAction();
    addPlayAction();
    addPauseAction();
    addBackwardAction();
    addForwardAction();
    addOpenAction();
  }

  /**
   * Processes file picker results.
   */
  @Override
  protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (resultCode == RESULT_OK) {
      switch (requestCode) {
        case FILE_PICKER:
          String filePath = data.getStringExtra(FilePicker.FILE_PATH_EXTRA);

          String trackName = new File(filePath).getName();
          playListAdapter.add(trackName);
          int position = playListAdapter.getPosition(trackName);

          playListContent.put(position, filePath);
          playListAdapter.notifyDataSetChanged();
          break;
        default:
          super.onActivityResult(requestCode, resultCode, data);
          break;
      }
    }
  }

  /**
   * Saves player configuration.
   */
  @Override
  public Object onRetainNonConfigurationInstance() {
    ConfigurationHolder configHolder = new ConfigurationHolder();
    configHolder.player = player;
    configHolder.playListAdapter = playListAdapter;
    configHolder.playListContent = playListContent;
    return configHolder;
  }

  /**
   * Adds action which starts next track when current one is finished.
   */
  private void addPlayerOnCompleteAction() {
    player.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {

      @Override
      public void onCompletion(MediaPlayer mp) {
        performForward();
      }
    });
  }

  /**
   * Adds action when user taps on the track name in playlist. New track is
   * started.
   */
  private void addSelectTrackAction() {
    playList.setOnItemClickListener(new AdapterView.OnItemClickListener() {

      @Override
      public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
        performPlayNewTrack(position);
      }
    });
  }

  /**
   * Adds action to play button. Continue playing if track was previously
   * paused.
   */
  private void addPlayAction() {
    ImageButton playButton = (ImageButton) findViewById(R.id.play_button);
    playButton.setOnClickListener(new View.OnClickListener() {

      @Override
      public void onClick(View v) {
        if (!player.isPlaying()) {
          player.start();
        }
      }
    });
  }

  /**
   * Adds pause button action.
   */
  private void addPauseAction() {
    ImageButton pauseButton = (ImageButton) findViewById(R.id.pause_button);
    pauseButton.setOnClickListener(new View.OnClickListener() {

      @Override
      public void onClick(View v) {
        if (player.isPlaying()) {
          player.pause();
        }
      }
    });
  }

  /**
   * Adds previous track in playlist play. If current track is the first in
   * playlist, the last one must be started.
   */
  private void addBackwardAction() {
    ImageButton backwardButton = (ImageButton) findViewById(R.id.bwd_button);
    backwardButton.setOnClickListener(new View.OnClickListener() {

      @Override
      public void onClick(View v) {
        int total = playListAdapter.getCount();
        if (total > 0) {
          int previous = currentlyPlayed - 1;
          if (previous < 0) {
            previous += total;
          }
          performPlayNewTrack(previous);
        }
      }
    });
  }

  /**
   * Adds next track in playlist play. If current track is the last in playlist,
   * the first one must be started.
   */
  private void addForwardAction() {
    ImageButton forwardButton = (ImageButton) findViewById(R.id.fwd_button);
    forwardButton.setOnClickListener(new View.OnClickListener() {

      @Override
      public void onClick(View v) {
        performForward();
      }
    });
  }

  /**
   * Starts file picker to open new track and add it to playlist.
   */
  private void addOpenAction() {
    ImageButton openButton = (ImageButton) findViewById(R.id.open_button);
    openButton.setOnClickListener(new View.OnClickListener() {

      @Override
      public void onClick(View v) {
        Intent intent = new Intent(Player.this, FilePicker.class);
        intent.putExtra(FilePicker.MIME_TYPE_EXTRA, "audio/*");
        startActivityForResult(intent, FILE_PICKER);
      }
    });
  }

  /**
   * Performs start of the track from the beginig.
   * 
   * @param selected position in playlist to start track.
   */
  private void performPlayNewTrack(int selected) {
    try {
      String trackPath = playListContent.get(selected);
      player.reset();
      player.setDataSource(trackPath);
      player.prepare();
      player.start();

      currentlyPlayed = selected;
    } catch (IOException e) {
      Log.e(TAG, "Error while try to play file", e);
    }
  }

  /**
   * Performs start of next track from playlist.
   */
  private void performForward() {
    int total = playListAdapter.getCount();
    if (total > 0) {
      int next = currentlyPlayed + 1;
      if (next >= total) {
        next -= total;
      }
      performPlayNewTrack(next);
    }
  }

  /**
   * Simple player configuration holder.
   * 
   * @author Anton Novikau
   */
  private class ConfigurationHolder {
    private Map<Integer, String> playListContent;

    private ArrayAdapter<String> playListAdapter;

    private MediaPlayer player;
  }
}
